Skip to content

Fix broken refactor of awaitable generator patching#21435

Merged
ilevkivskyi merged 2 commits intopython:masterfrom
ilevkivskyi:fix-split-impl-untyped-coro
May 8, 2026
Merged

Fix broken refactor of awaitable generator patching#21435
ilevkivskyi merged 2 commits intopython:masterfrom
ilevkivskyi:fix-split-impl-untyped-coro

Conversation

@ilevkivskyi
Copy link
Copy Markdown
Member

Fixes #21426

Fix is straightforward: make the new logic more 1:1 with the old one (which was not the case for untyped functions).

@ilevkivskyi ilevkivskyi requested review from JukkaL and hauntsaninja May 7, 2026 14:08
@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Collaborator

@JukkaL JukkaL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to regress unannotated functions -- their bodies may now be checked (but this wasn't the case in 1.20):

import types

@types.coroutine
def f(x):
    1 + "x"  # Error (but shouldn't be, since no annotation)
    yield

If I omit @types.coroutine, there is no error reported.

@ilevkivskyi
Copy link
Copy Markdown
Member Author

Hm, this is kind of a pre-existing problem, I can reproduce this on older versions with e.g. a deferral (or otherwise force re-visiting the function). But now the issue is more prominent, because with two-phase checking every function is in some sense deferred.

Patching the defn.type in-place is a sketchy thing (and also all the code around awaitable generators is sketchy, but I knew about this when I started the whole two-phase checking thing).

After some thinking, we probably shouldn't do the wrapping at all for dynamic functions for consistency with regular async def:

async def f(): ...
reveal_type(f)  # "def () -> Any", not "def () -> Coroutine[Any, Any, Any]"

Or vice-versa, we should wrap both. So what would it be? @JukkaL

(to be clear both ways have relatively simple fixes)

@hauntsaninja
Copy link
Copy Markdown
Collaborator

hauntsaninja commented May 7, 2026

Let's try wrapping both!

@ilevkivskyi
Copy link
Copy Markdown
Member Author

Let's try wrapping both!

OK, let's see how it works. Btw there is another quirk that needed fixing, the

Use "-> None" if function does not return a value

note is added based on some random heuristics. I made some changes to preserve the current behavior (just to minimize number of ~unrelated changes in this PR)

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@ilevkivskyi ilevkivskyi force-pushed the fix-split-impl-untyped-coro branch from 6fb2f40 to 6a6aa49 Compare May 7, 2026 21:44
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 7, 2026

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

@ilevkivskyi
Copy link
Copy Markdown
Member Author

Let's try wrapping both!

OK, let's see how it works

It didn't really work, whatever direction I go, a whole can of worms opens. So let's just fix the regression. The PR as it is now should be strictly better than both 2.0 (no crash) and 1.20 (dynamic functions don't stop being such when deferred).

@agners
Copy link
Copy Markdown

agners commented May 8, 2026

I can confirm this fixes the issue in our code base. Thanks for picking this up!

@ilevkivskyi ilevkivskyi merged commit 675b6bf into python:master May 8, 2026
24 checks passed
@ilevkivskyi ilevkivskyi deleted the fix-split-impl-untyped-coro branch May 8, 2026 10:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[2.0 regression] INTERNAL ERROR: AssertionError in visit_decorator_inner on @types.coroutine generator function

4 participants